/*
    SEL - Simple DirectMedia Layer Extension Library
    Copyright (C) 2001 Matej Knopp <knopp@users.sf.net>

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public
    License as published by the Free Software Foundation; either
    version 2 of the License, or (at your option) any later version.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Library General Public License for more details.

    You should have received a copy of the GNU Library General Public
    License along with this library; if not, write to the Free
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/

#ifndef __sel_font_h__
#define __sel_font_h__

#include "../base/sdl.h"
#include "../base/object.h"
#include <vector>
#include <string>

namespace SEL
{

class Surface;

//! A character of a font.
/*!
  The FontCharacter class contains the information and graphical data
  of one character of the font. The character has some
  attributes associated with it (like width and the character code).
  
  The graphical data is stored in two surfaces. One is original, it's
  format is the same as the format of the source surface and one
  is converted, optimized for fast bliting to the destination surface.
 */
class FontCharacter
{
public:
	//! Create a new character, optionally set the original surface.
	/*!
	  \param surface pointer to the original surface.
	 */
	FontCharacter (Surface *surface = NULL);
	
	//! Delete the character.
	/*!
	  The both surfaces are destroyed (their reference count
	  is decreased by 1).
	 */
	~FontCharacter ();
	
	//! Get the pointer to the original surface.
	/*!
	  \return Pointer to the original surface or NULL if none.
	 */
	Surface *originalSurface ()		{ return m_original_surface; }

	//! Get the const pointer to the original surface.
	/*!
	  \return Pointer to the original surface or NULL if none.
	 */
	const Surface *originalSurface () const	{ return m_original_surface; }
	
	//! Set the original surface.
	/*!
	  \note The previous original surface is not freed.
	  
	  \param surface pointer to the new original surface.
	 */
	void setOriginalSurface (Surface *surface);
	
	//! Get the converted surface.
	/*!
	  \return Pointer to the converted surface or NULL if none.
	 */
	Surface *convertedSurface () 		{ return m_converted_surface; }

	//! Get the constant converted surface.
	/*!
	  \return Pointer to the converted surface or NULL if none.
	 */
	const Surface *convertedSurface () const
						{ return m_converted_surface; }

	
	//! Set the converted surface.
	/*!
	  \note The previous converted surface is not freed.
	  
	  \param surface the pointer to the new converted surface.
	 */
	void setConvertedSurface (Surface *surface);
	
	//! Convert the original surface to the format that allows
	//! optimized blit onto a surface with given format and flags.
	/*!
	  \note The prevous converted surface is freed.
	  
	  \param dest_fmt the pixel format of the destination surface.
	  \param dest_flags the flags of the destination surface.
	 */
	void convertSurface (const SDL::PixelFormat &dest_fmt,
			     Uint32 dest_flags);
			     
	//! Get the width of the character.
	Uint16 width () const			{ return m_width; }
	
	//! Set the width of the character.
	/*!
	  \param width the new width of the character.
	 */
	void setWidth (Uint16 width);
	
	//! Set the default width of the character.
	/*!
	  Sets the width of the character according to the surface that
	  represents it's graphical data.
	 */
	void resetWidth ();
	
	//! Get the character code of the character.
	Uint16 character () const		{ return m_character; }
	
	//! Set the character code of the character.
	/*!
	  \param character the new character code.
	 */
	void setCharacter (Uint16 character)	{ m_character = character; }

protected:
	Surface *m_original_surface;
	Surface *m_converted_surface;
	Uint16 m_width;
	Uint16 m_character;
};

//! This class represents a font.
/*!
  The font is an array of characters with some common attributes.
  
  The font is normally created from a surface that contains transparent
  areas (alpha or colorkeyed) which are used to determine the borders
  of particular characters. The characters drawn in the surface are
  supposed to be ordered left to right according to the provided map
  with a gap between them of size that is equal or greater than the
  specified minimal gap size.
  
  This same applies to creating fonts from resources. For more information
  about the font resource see the ResourceFont class.
 */
class Font : public Object
{
public:
	//! Create a new font from the specified source.
	/*!
	  \param src the source surface (must have either the alpha layer or 
	   set the color key)
	  \param map the order of the characters that are drawn in the source
	   surface.
	  \param space_width the width of the space (in pixels).
	  \param min_gap_width the minimal count of empty lines between
	   characters.
	  \param alpha_treshold the minimal value of a pixel in alpha
	   channel that is considered opaque.
	 */
	Font (Surface *src,
	      const std::string &map,
	      Uint16 space_width,
	      Uint16 min_gap_width,
	      Uint8 alpha_treshold);
	      
	//! Destroy the font and it's characters.
	virtual ~Font ();
	
	//! Get the pointer to the target surface.
	Surface *targetSurface () 		{ return m_target_surface; }
	
	//! Get the constant pointer to the target surface.
	const Surface *targetSurface () const	{ return m_target_surface; }
	
	//! Set the target surface.
	/*!
	  The target surface is a surface to which the text will be drawn.
	  After setting the target surface all the characters are optimized
	  for the fastest possible blit.
	  
	  \param surface pointer to the new target surface.
	 */
	void setTargetSurface (Surface *surface);
	
	//! Release the current target surface.
	void releaseTargetSurface ();
	
	//! Return the pointer to the character with given character code.
	/*!
	  \param character the specified character code.
	 */
	FontCharacter *characterMap (Uint8 ch) 	
						{ return m_characters [m_character_map [ch]]; }

	//! Return the const pointer to the character with given character code.
	/*!
	  \param character the specified character code.
	 */
	const FontCharacter *characterMap (Uint8 ch) const
						{ return m_characters [m_character_map [ch]]; }
	
	//! Return the pointer to the character with given index.
	/*!
	  \param index the index of the character in the characters array.
	 */
	FontCharacter *character (Uint16 index) { return m_characters [index]; }

	//! Return the constant pointer to the character with given index.
	/*!
	  \param index the index of the character in the characters array.
	 */
	const FontCharacter *character (Uint16 index) const	
						{ return m_characters [index]; }
	
	//! Return the width of the space.
	Uint16 spaceWidth () const		{ return m_space_width; }
	
	//! Set the width of the space.
	/*!
	  \param width the width of the space.
	 */
	void setSpaceWidth (Uint16 width);
	
	//! Get the additional horizontal spacing.
	Sint16 hSpacing () const		{ return m_h_spacing; }
	
	//! Set the additional horizontal spacing.
	/*!
	  Sets the additional spacing between the characters.
	  \note The spacing may be negative.
	  
	  \param spacing the new horizontal spacing.
	 */
	void setHSpacing (Sint16 spacing);
	
	//! Get the additional vertical spacing.	
	Sint16 vSpacing () const		{ return m_v_spacing; }
	
	//! Set the additional vertical spacing.
	/*!
	  Sets the additional spacing between the lines.
	  \note The spacing may be negative.
	  
	  \param specing the new vertical spacing.
	 */
	void setVSpacing (Sint16 spacing);
	
	//! Get the height of the font.
	/*!
	  \note The height of all characters in the font is common.
	 */
	Uint16 height () const			{ return m_height; }
	
	//! Compute the width of the specified text.
	/*! 
	  \param text the text.
	 */
	Sint16 computeWidth (const std::string &text) const;
	
	//! Compute the height of the specified text.
	/*!
	  \param text the text.
	 */
	Sint16 computeHeight (const std::string &text) const;
	
	//! Print the specified text at the given position to the
	//! destination surface.
	/*!
	  \param x,y the target coordinates
	  \param text the text.
	 */
	void print (Sint16 x, Sint16 y, const std::string &text);

protected:
	std::vector<FontCharacter*> m_characters;
	Uint16 m_character_map[256];
	Uint16 m_space_width;
	Uint16 m_height;
	Sint16 m_h_spacing;
	Sint16 m_v_spacing;
	Surface *m_target_surface;

	static bool pixelTransparent (Surface *surface, 
				      Uint32 pixeladdr,
				      Uint8 alpha_treshold);
	static bool vLineTransparent (Surface *surface, 
				      Uint16 line, 
				      Uint8 alpha_treshold);
	static bool hLineTransparent (Surface *surface, 
				      Uint16 line, 
				      Uint8 alpha_treshold);
	void importFont (Surface *src, const std::string &map,
			 Uint16 min_gap_width, Uint16 alpha_treshold);
};

} // namespace SEL

#endif // __sel_font_h__
